import unittest
import os
from typing import Any, Dict, List, Optional
import appbuilder
from appbuilder import Manifest
from appbuilder import manifest, manifest_parameter


@unittest.skipUnless(os.getenv("TEST_CASE", "UNKNOWN") == "CPU_SERIAL", "")
class TestManifest(unittest.TestCase):
    def setUp(self):
        """
        设置环境变量。

        Args:
            无参数，默认值为空。

        Returns:
            无返回值，方法中执行了环境变量的赋值操作。
        """
        os.environ["APPBUILDER_TOKEN"] = (
            "your api key"
        )
        self.app_id = "7cc4c21f-0e25-4a76-baf7-01a2b923a1a7"

    def test_google_style(self):
        # Generated by vscode plugin
        # https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring
        def google_style(
            name: str,
            val: str = None,
            val_obj: Optional[Any] = None,
            val_list: List[str] = None,
            data: Dict[str, int] = None,
        ) -> str:
            """Google style docstring.

            Args:
                name (str): Name of object.
                val (str, optional): Value of obj. Defaults to None.
                val_obj (Optional[Any], optional): Real object reference. Defaults to None.
                val_list (List[str], optional): List of items with object. Defaults to None.
                data (Dict[str, int], optional): Data along with object. Defaults to None.

            Returns:
                str: Styled string.
            """
            return ""

        manifest_from_function = appbuilder.Manifest.from_function(google_style)

        # 断言顶层的结构
        assert manifest_from_function.type == "function", "Type does not match 'function'"
        assert (
            manifest_from_function.function["name"] == "google_style"
        ), "Function name does not match 'google_style'"
        assert (
            manifest_from_function.function["description"]
            == """Google style docstring.

            Args:
                name (str): Name of object.
                val (str, optional): Value of obj. Defaults to None.
                val_obj (Optional[Any], optional): Real object reference. Defaults to None.
                val_list (List[str], optional): List of items with object. Defaults to None.
                data (Dict[str, int], optional): Data along with object. Defaults to None.

            Returns:
                str: Styled string.
            """
        ), "Description does not match"

        # 断言参数结构
        parameters = manifest_from_function.function["parameters"]
        assert parameters["type"] == "object", "Parameters type does not match 'object'"
        assert "properties" in parameters, "Properties not found in parameters"

        # 断言各个参数的类型和描述
        properties = parameters["properties"]

        # name 参数
        assert "name" in properties, "'name' parameter missing"
        # 添加类型检查时的调试信息
        try:
            assert (
                properties["name"]["type"] == "str"
            ), f"'name' type does not match 'str'. Actual type: {properties['name']['type']}"
        except AssertionError as e:
            print(f"Debug Info: Actual 'name' type is {properties['name']['type']}")
            raise e  # 重新抛出异常

        # val 参数
        assert "val" in properties, "'val' parameter missing"
        assert properties["val"]["type"] == "str", "'val' type does not match 'str'"

        # val_obj 参数
        assert "val_obj" in properties, "'val_obj' parameter missing"
        assert (
            properties["val_obj"]["type"] == "Optional[Any]"
        ), "'val_obj' type does not match 'object'"

        # val_list 参数
        assert "val_list" in properties, "'val_list' parameter missing"
        assert (
            properties["val_list"]["type"] == "List[str]"
        ), "'val_list' type does not match 'array'"

        # data 参数
        assert "data" in properties, "'data' parameter missing"
        assert (
            properties["data"]["type"] == "Dict[str, int]"
        ), "'data' type does not match 'object'"

        # 断言必需参数
        assert "required" in parameters, "'required' field missing in parameters"
        assert parameters["required"] == ["name"], "'required' does not match ['name']"

    def test_google_style_bad_args_return_dict(self):
        def func(
            bad_param: str,
            bad_generic_param: List[str],
            bad_format: int,
            val: str = None,
        ) -> Dict[str, str]:
            """Google style docstring.

            Args:
                bad param (str): Bad parameter, name contains whitespace.
                bad_generic_param (List<str>): Bad generic parameter, use <> instead of []
                bad_format (int) Bad arg doc format, lost :.
                val (str    ,      optional): Value of obj. Defaults to None.

            Returns:
                Dict[str, str]: Returns a dict.
            """
            return ""

        manifest_from_function = appbuilder.Manifest.from_function(func)
        # 断言顶层的结构
        assert manifest_from_function.type == "function", "Type does not match 'function'"
        assert (
            manifest_from_function.function["name"] == "func"
        ), "Function name does not match 'func'"
        assert (
            manifest_from_function.function["description"]
            == """Google style docstring.

            Args:
                bad param (str): Bad parameter, name contains whitespace.
                bad_generic_param (List<str>): Bad generic parameter, use <> instead of []
                bad_format (int) Bad arg doc format, lost :.
                val (str    ,      optional): Value of obj. Defaults to None.

            Returns:
                Dict[str, str]: Returns a dict.
            """
        ), "Description does not match"

        # 断言参数结构
        parameters = manifest_from_function.function["parameters"]
        assert parameters["type"] == "object", "Parameters type does not match 'object'"
        assert "properties" in parameters, "Properties not found in parameters"

        # 断言各个参数的类型和描述
        properties = parameters["properties"]

        # bad_param 参数
        assert "bad_param" in properties, "'bad_param' parameter missing"
        assert (
            properties["bad_param"]["type"] == "str"
        ), "'bad_param' type does not match 'str'"

        # bad_format 参数
        assert "bad_format" in properties, "'bad_format' parameter missing"
        assert (
            properties["bad_format"]["type"] == "int"
        ), "'bad_format' type does not match 'int'"

        # val 参数
        assert "val" in properties, "'val' parameter missing"
        assert properties["val"]["type"] == "str", "'val' type does not match 'str'"

        # 断言必需参数
        assert "required" in parameters, "'required' field missing in parameters"
        assert parameters["required"] == [
            "bad_param",
            "bad_generic_param",
            "bad_format",
        ], "'required' does not match expected required parameters"

        # 断言没有多余参数
        assert len(properties) == 4, "Unexpected number of parameters in properties"

    def test_google_style_no_return(self):
        def func(
            name: str,
        ):
            """Google style docstring.

            Args:
                name (str): Name of object.

            """
            return ""

        manifest_from_function = appbuilder.Manifest.from_function(func)
        # 断言顶层的结构
        assert manifest_from_function.type == "function", "Type does not match 'function'"
        assert (
            manifest_from_function.function["name"] == "func"
        ), "Function name does not match 'func'"
        assert (
            manifest_from_function.function["description"]
            == """Google style docstring.

            Args:
                name (str): Name of object.

            """
        ), "Description does not match"

        # 断言参数结构
        parameters = manifest_from_function.function["parameters"]
        assert parameters["type"] == "object", "Parameters type does not match 'object'"
        assert "properties" in parameters, "Properties not found in parameters"

        # 断言参数类型和描述
        properties = parameters["properties"]

        # name 参数
        assert "name" in properties, "'name' parameter missing"
        assert properties["name"]["type"] == "str", "'name' type does not match 'str'"

        # 断言必需参数
        assert "required" in parameters, "'required' field missing in parameters"
        assert parameters["required"] == ["name"], "'required' does not match ['name']"

        # 断言没有["parameters"][1]的参数了
        assert not (
            "parameters" in manifest_from_function.function
            and len(manifest_from_function.function["parameters"]) == 1
        )

    def test_no_doc(self):
        def func(
            name: str,
            /,
            *args,
            val: str = None,
            val_obj: Optional[Any] = None,
            data: Dict[str, int] = None,
            **kwargs,
        ) -> str:
            return ""

        # 断言这里会抛出缺少文档字符串的 ValueError 异常
        try:
            manifest_from_function = appbuilder.Manifest.from_function(func)
        except ValueError as e:
            assert (
                str(e) == "函数 func 缺少文档字符串"
            ), "未抛出预期的 ValueError 或信息不匹配"

    def test_decorator_google_style_basic(self):
        @manifest(description="Function with required parameter.")
        def func(
            name: str,
        ) -> str:
            """Function with required parameter.

            Args:
                name (str): Name of object.

            Returns:
                str: Styled string.
            """
            return ""

        # 获取装饰器生成的 Manifest
        manifest_from_function = func.__ab_manifest__

        # 断言顶层的结构
        assert manifest_from_function.type == "function", "Type does not match 'function'"
        assert (
            manifest_from_function.function["name"] == "func"
        ), "Function name does not match 'func'"
        assert (
            manifest_from_function.function["description"]
            == "Function with required parameter."
        ), "Description does not match"

        # 断言参数结构
        parameters = manifest_from_function.function["parameters"]
        assert parameters["type"] == "object", "Parameters type does not match 'object'"
        assert "properties" in parameters, "Properties not found in parameters"

        # 断言各个参数的类型和描述
        properties = parameters["properties"]

        # name 参数
        assert "name" in properties, "'name' parameter missing"
        assert properties["name"]["type"] == "str", "'name' type does not match 'str'"
        assert (
            properties["name"]["description"] == None
        ), "'name' description does not match"

        # 断言必需参数
        assert "required" in parameters, "'required' field missing in parameters"
        assert parameters["required"] == ["name"], "'required' does not match ['name']"

    def test_manifest_decorator(self):
        @appbuilder.manifest(
            description="获取指定中国城市的当前天气信息。仅支持中国城市的天气查询。参数 `location` 为中国城市名称，其他国家城市不支持天气查询。"
        )
        @appbuilder.manifest_parameter(
            name="location", description="城市名，例如：北京。"
        )
        @appbuilder.manifest_parameter(
            name="unit", description="温度单位，支持 'celsius' 或 'fahrenheit'"
        )
        # 定义示例函数
        def get_current_weather(location: str, unit) -> str:
            return "北京今天25度"
        manifest_from_function = appbuilder.Manifest.from_function(get_current_weather)
        assert manifest_from_function.function.get("description") is not None


if __name__ == "__main__":
    unittest.main()
